package cn.wmw.xyy.service.impl;

import cn.wmw.xyy.bo.PayTxLocalBo;
import cn.wmw.xyy.domain.PayFlow;
import cn.wmw.xyy.domain.PayOrder;
import cn.wmw.xyy.dto.AlipayNotifyDto;
import cn.wmw.xyy.dto.PayApplyDto;
import cn.wmw.xyy.exception.GlobalException;
import cn.wmw.xyy.exception.GlobalExceptionEnum;
import cn.wmw.xyy.mapper.PayOrderMapper;
import cn.wmw.xyy.properties.AliPayProperties;
import cn.wmw.xyy.service.IPayFlowService;
import cn.wmw.xyy.service.IPayOrderService;
import cn.wmw.xyy.utils.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wmw
 * @since 2023-01-10
 */
@Service
@Slf4j
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {

    @Autowired
    private AliPayProperties aliPayProperties;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private IPayFlowService payFlowService;

    @Override
    public PayOrder selectByOrderNo(String orderNo) {
        Wrapper<PayOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no", orderNo);
        return selectOne(wrapper);
    }

    @Override
    public String apply(PayApplyDto payApplyDto) {
        String orderNo = payApplyDto.getOrderNo();
        String callUrl = payApplyDto.getCallUrl();
        PayOrder payOrder = this.selectByOrderNo(orderNo);
        AssertUtil.isNotNull(payOrder, GlobalExceptionEnum.ERROR);
        AssertUtil.isTrue(PayOrder.WAIT_PAY.equals(payOrder.getPayStatus()), GlobalExceptionEnum.ERROR);
        if (PayOrder.ALI_PAY.equals(payOrder.getPayType())){
            return aliPay(payOrder,callUrl);
        }else if (PayOrder.WX_PAY.equals(payOrder.getPayType())){

        }else if (PayOrder.BANK_PAY.equals(payOrder.getPayType())){

        }
        throw new GlobalException(GlobalExceptionEnum.ERROR);
    }

    /**
     * 发起支付
     * @param payOrder
     * @param callUrl
     * @return
     */
    private String aliPay(PayOrder payOrder, String callUrl) {
        try {
            // 1. 发起网站支付调用
            String orderNo = payOrder.getOrderNo();
            String subject = payOrder.getSubject();
            String amount = payOrder.getAmount().toString();
            AlipayTradePagePayResponse response = Factory.Payment.Page().pay(subject, orderNo, amount, callUrl);
            // 2. 处理响应或异常
            if (ResponseChecker.success(response)) {
                log.info("调用支付成功，订单号为：" + payOrder.getOrderNo());
                return response.getBody();
            } else {
                log.error("调用失败，原因：" + response.getBody() + "，" + response.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("调用遭遇异常，原因：" + e.getMessage());
            throw new GlobalException(GlobalExceptionEnum.ERROR);
        }
        return "";
    }

    @Override
    public String callback(AlipayNotifyDto alipayNotifyDto) {
        //业务校验
        try {
            String appId = alipayNotifyDto.getApp_id();
            String totalAmount = alipayNotifyDto.getTotal_amount();
            String outTradeNo = alipayNotifyDto.getOut_trade_no();
            String tradeStatus = alipayNotifyDto.getTrade_status();
            Map map = JSON.parseObject(JSON.toJSONString(alipayNotifyDto), Map.class);
            Boolean aBoolean = Factory.Payment.Common().verifyNotify(map);
            //判断验签状态
            if (!aBoolean){
                return "success";
            }
            //校验appid
            if (!aliPayProperties.getAppId().equals(appId)){
                return "success";
            }
            PayOrder payOrder = selectByOrderNo(outTradeNo);
            if (payOrder == null){
                return "success";
            }
            if (payOrder.getAmount().compareTo(new BigDecimal(totalAmount)) == -1){
                return "success";
            }
            if (!AlipayNotifyDto.TRADE_SUCCESS.equals(tradeStatus)){
                return "success";
            }
            // 校验本地支付单
            Integer payStatus = payOrder.getPayStatus();
            if (PayOrder.SUCCESS_PAY.equals(payStatus)){
                return "success";
            }
            if (PayOrder.CANCEL_PAY.equals(payStatus) || PayOrder.FAIL_PAY.equals(payStatus)){
                AlipayTradeRefundResponse refund = Factory.Payment.Common().refund(outTradeNo, totalAmount);
                String code = refund.getCode();
                if ("10000".equals(code)){
                    log.error("出异常啦，快修bug");
                }
            }
            if (!PayOrder.WAIT_PAY.equals(payStatus)){
                log.error("出异常啦，快修bug");
            }
            // 修改支付单，保存流水，发送事务消息完成
            PayTxLocalBo payTxLocalBo = init(payOrder);
            String extParams = payOrder.getExtParams();
            Message<String> message = MessageBuilder.withPayload(extParams).build();
            TransactionSendResult sendMessageInTransaction = rocketMQTemplate.sendMessageInTransaction(
                    "tx-pay-order-handle-produce",
                    "pay-local-order-topic:pay-local-order-tag",
                    message,
                    payTxLocalBo
            );
            SendStatus sendStatus = sendMessageInTransaction.getSendStatus();
            if (!SendStatus.SEND_OK.equals(sendStatus)){
                log.error("出异常啦，快修bug");
                return "fail";
            }
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }
    }


    private static PayTxLocalBo init(PayOrder payOrder) {
        payOrder.setPayStatus(PayOrder.SUCCESS_PAY);
        PayFlow payFlow = new PayFlow();
        Date date = new Date();
        payFlow.setNotifyTime(date);
        payFlow.setSubject(payOrder.getSubject());
        payFlow.setOutTradeNo(payOrder.getOrderNo());
        payFlow.setTotalAmount(payOrder.getAmount());
        payFlow.setTradeStatus(PayFlow.SUCCESS_PAY.toString());
        return new PayTxLocalBo(payOrder,payFlow);
    }

    public void payOrderLocalHandle(PayTxLocalBo payTxLocalBo){
        PayFlow payFlow = payTxLocalBo.getPayFlow();
        PayOrder payOrder = payTxLocalBo.getPayOrder();
        updateById(payOrder);
        payFlowService.insert(payFlow);
    }

}
